package com.leyou.sh.search.service.impl;

import com.leyou.sh.item.client.ItemClient;
import com.leyou.sh.common.dto.PageDTO;
import com.leyou.sh.item.dto.*;
import com.leyou.sh.search.entity.Goods;
import com.leyou.sh.search.repository.GoodsRepository;
import com.leyou.sh.search.service.IndexService;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author balisong_fcs
 * @date 2021/1/5 19:08
 * @desc
 */
@Service
@Slf4j
public class IndexServiceImpl implements IndexService {
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private GoodsRepository goodsRepository;

    private int page = 1;
    //1.item中查找数据
    @Override
    public void loadData() {
        /**
         * 删除es中已存在得索引库
         */
        try {
            this.goodsRepository.deleteIndex();
            log.info("索引库删除成功");
        } catch (Exception e) {
            log.info("没有索引库需要删除");
        }
        /**
         * 新建索引库并设置mappings映射以及组合分词器
         */
        this.goodsRepository.createIndex("{\n" +
                "  \"settings\": {\n" +
                "    \"analysis\": {\n" +
                "      \"analyzer\": {\n" +
                "        \"my_pinyin\": {\n" +
                "          \"tokenizer\": \"ik_smart\",\n" +
                "          \"filter\": [\n" +
                "            \"py\"\n" +
                "          ]\n" +
                "        }\n" +
                "      },\n" +
                "      \"filter\": {\n" +
                "        \"py\": {\n" +
                "\t\t  \"type\": \"pinyin\",\n" +
                "          \"keep_full_pinyin\": true,\n" +
                "          \"keep_joined_full_pinyin\": true,\n" +
                "          \"keep_original\": true,\n" +
                "          \"limit_first_letter_length\": 16,\n" +
                "          \"remove_duplicated_term\": true\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  },\n" +
                "  \"mappings\": {\n" +
                "    \"properties\": {\n" +
                "      \"id\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"suggestion\": {\n" +
                "        \"type\": \"completion\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"title\":{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"my_pinyin\",\n" +
                "        \"search_analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"image\":{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"updateTime\":{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"specs\":{\n" +
                "        \"type\": \"nested\",\n" +
                "        \"properties\": {\n" +
                "          \"name\":{\"type\": \"keyword\" },\n" +
                "          \"value\":{\"type\": \"keyword\" }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "}");
        log.info("删除索引成功");
        log.info("开始搜索导入数据");
        /**
         * 循环分页查询所有数据
         */
        while (true) {
            //调取方法获取分页查询所有Spu数据
            PageDTO<SpuDTO> spuDTOPageDTO = this.itemClient.querySpuByPage(null, null, null, page, 50, true);
            //判断查询得数据
            if (0 == spuDTOPageDTO.getTotalPage()) {
                break;
            }
            List<Goods> goodsList = spuDTOPageDTO.getItems()
                    .stream()
                    .map(this::buildGoods)
                    .collect(Collectors.toList());
            log.info("搜索数据完成");
            //2.包数据保存到索引库中
            this.goodsRepository.saveAll(goodsList);
            log.info("注入索引库完成");

            page++;
           //当下一次要查询得页码比总页码多,停止查询
            if (page > spuDTOPageDTO.getTotalPage()) {
                break;
            }
        }

    }
    @Override
    public Goods buildGoods(SpuDTO spuDTO) {
        Goods goods = new Goods();
        BeanUtils.copyProperties(spuDTO, goods);

        //自动补全候选内容,分别包含,品牌/分类/品牌+分类/分类+品牌/商品名称/品牌+商品名称
        BrandDTO brandDTO = this.itemClient.queryBrandById(spuDTO.getBrandId());
        //取 ( 之前得字符串 品牌名
        String brandName = StringUtils.substringBefore(brandDTO.getName(), "(");
        //分类名
        CategoryDTO categoryDTO = this.itemClient.queryCategoryById(spuDTO.getCid3());
        String categoryName = categoryDTO.getName();

        //1:将suggestion候选补全词汇可能得情况编辑设置
        List<String> suggs = new ArrayList<>();
        suggs.add(brandName);
        suggs.add(categoryName);
        suggs.add(brandName + categoryName);
        suggs.add(categoryName + brandName);
        suggs.add(spuDTO.getName());
        suggs.add(brandName + spuDTO.getName());

        goods.setSuggestion(suggs);

        //2:设置作为搜索索引得title得值
        String title = null;
        title = spuDTO.getName() + (spuDTO.getName().contains(categoryName) ? "" : categoryName) + (spuDTO.getName().contains(brandName) ? "" : brandName);

        goods.setTitle(title);

        //3:设置categoryId得值
        goods.setCategoryId(spuDTO.getCid3());
        //4:设置image得值
        List<SkuDTO> skuDTOS = this.itemClient.querySkuBySpuId(spuDTO.getId());

        String image = (skuDTOS.get(0).getImages().split(","))[0];
        goods.setImage(image);
        //5:设置prices得值
        Set<Long> price = new HashSet<>();
        Long sold = 0L;
        for (SkuDTO skuDTO : skuDTOS) {
            price.add(skuDTO.getPrice());
            sold += skuDTO.getSold();
        }
        goods.setPrices(price);
        goods.setSold(sold);
        //6:设置更新时间
        goods.setUpdateTime(new Date());

        //设置specs
        List<Map<String, Object>> specsResult = new ArrayList<>();

        List<SpecParamDTO> paramDTOS = this.itemClient.querySpecParamValue(spuDTO.getId(), true);
        paramDTOS.forEach(specParamDTO -> {
            Map<String, Object> result = new HashMap<>();
            //name，规格参数的名称，value，规格参数的值
            result.put("name", specParamDTO.getName());
            //保存值应该给可以进行区间处理的值，划分区间
            result.put("value", chooseSegment(specParamDTO));
            specsResult.add(result);
        });
        goods.setSpecs(specsResult);


        return goods;
    }

    @Override
    public void deleteById(Long id) {
        this.goodsRepository.deleteById(id);
    }

    @Override
    public void createIndexById(Long id) {
        PageDTO<SpuDTO> spuDTOPageDTO = this.itemClient.querySpuByPage(null, null, Math.toIntExact(id), 1, 1, true);
        //查到商品才进行上架处理
        if (spuDTOPageDTO.getTotalPage() == 1) {
            SpuDTO spuDTO = spuDTOPageDTO.getItems().get(0);
            Goods goods = buildGoods(spuDTO);
            this.goodsRepository.save(goods);
        }
    }


    /**
     * 将spu属性中,可以划分区间得参数,划分区间存储
     * @param p
     * @return
     */
    private Object chooseSegment(SpecParamDTO p) {
        Object value = p.getValue();
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        if (!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection) {
            return value;
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }
}
